多级分类、菜单等的数据库设计(一张表),以及mybatis

您所在的位置:网站首页 mysql 角色表设计分列查询 多级分类、菜单等的数据库设计(一张表),以及mybatis

多级分类、菜单等的数据库设计(一张表),以及mybatis

2024-01-09 06:43| 来源: 网络整理| 查看: 265

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

注重版权,转载请注明原作者和原文链接🤤 作者:Yuan-Programmer的🤤 进来的小伙伴点点赞呀😋 一、前言

我们在项目开发过程,经常会遇到有文章分类分栏,菜单分类,视频分类等多级分类

那么这种多级分类我们在数据中又是如何设计的呢?在mybatis查询过程中又是如何多级查询的呢?

别着急,今年我们来解决这个需求,

当然,解决的方法有很多,这里我只介绍我自己使用的一种,有更好的方法可以评论区评论大家一起探讨

本次用到了 Maven工程、Swagger、RESTful接口风格、MyBatis-Plus

整体目录结构如下 在这里插入图片描述

二、问题需求

以文章分类为例(这里以二级分类举例,三级、四级甚至多级会了二级的之后可以自行思考)

博客项目中少不了文章分类,如下图所示,那么在数据库如何只使用一张表、一条SQL语句就能完美实现多级目录结构的存储和查询 在这里插入图片描述

三、数据库设计

我们需要设计三个字段

字段名类型注释idint这个不用说了吧,主键namevarchar分类名称parent_idint指向父级分类的ID,如果是父级分类则填0,如果是子分类则填父级分类的ID

接下来我们在mysql中创建出来 在这里插入图片描述

四、SQL多级分类查询

不知道大家都有没有用过 join 这个关键字呢,想必大家都挺少用到的吧,忘记的同学记得先去补补 join 的知识哦

采用 left join 左拼接的查询方式,完整的查询语句如下:

SELECT x.id AS parentId, x.name AS parentName, y.id AS childrenId ,y.name AS childrenName FROM xy_category AS x LEFT JOIN xy_category AS y ON y.parent_id = x.id WHERE x.parent_id = 0

查询结果如下(所有分类结构): 在这里插入图片描述 当然你也可以指定某个父级分类,查询它所有的子分类,只需要改变一下 where 的条件就行了 在这里插入图片描述 是不是就满足了我们的需求了呢,接下来我们在项目MyBatis-Plus中实现多级分类查询

查询SQL语句我们已经写出来了,难的是如何存储这样的结构数据,别着急慢慢来

五、项目结构搭建

先把完整结构创建完成,这个大家应该都很熟悉了吧

我这里使用的MyBatis-Plus,操作都差不多,用MyBatis也可以

(1)创建实体类 /** * FileName: Category * Author: 小袁 * Date: 2022/4/15 10:42 * Description: 分类实体 */ @Data @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) // 调用Setting方法后 回传对象 public class Category { /** * 分类ID */ @TableId(value = "id", type = IdType.AUTO) private Integer id; /** * 分类栏目名称 */ private String name; /** * 父级栏目 */ private Integer parent_id; } (2)创建DAO /** * FileName: CategoryMapper * Author: 小袁 * Date: 2022/4/15 10:52 * Description: 分类DAO */ @Repository public interface CategoryMapper extends BaseMapper { /** * 查询所有分类的目录结构 * @return */ List findCategoryList(); /** * 通过某个父级分类的ID查询该父级的所有子分类 * @param id * @return */ CategoryParentVo getCategoryById(Integer id); } (3)创建业务层

我这里把完整的增删改查全部放出来了,这是我之前做的博客项目,可自行删减 R 这个类是统一结果返回类,前后端分析基本都是这样操作,网上也有很多模板

service -- 接口 /** * FileName: CategoryService * Author: 小袁 * Date: 2022/4/15 10:52 * Description: 分类栏目 Service */ public interface CategoryService extends IService { /** * 新增分类栏目数据 * @param category * @return */ R insert(Category category); /** * 根据分类栏目的ID进行修改数据 * @param category * @return */ R modify(Category category); /** * 根据分类栏目的ID进行删除 * @param id * @return */ R remove(Integer id); /** * 通过某个父级分类的ID查询该父级的所有子分类 * @param id * @return */ R getCategoryById(Integer id); /** * 查询所有分类的目录结构 * @return */ R listCategory(); } servieImpl -- 实现类 /** * FileName: CategoryServiceImpl * Author: 小袁 * Date: 2022/4/15 10:54 * Description: 分类栏目的实现类 */ @Service @Transactional public class CategoryServiceImpl extends ServiceImpl implements CategoryService { @Autowired private CategoryMapper categoryMapper; @Override public R insert(Category category) { return categoryMapper.insert(category) == 0 ? R.error() : R.ok(); } @Override public R modify(Category category) { return categoryMapper.updateById(category) == 0 ? R.error() : R.ok(); } @Override public R remove(Integer id) { QueryWrapper wrapper = new QueryWrapper(); wrapper.eq("id", id); wrapper.or(); wrapper.eq("parent_id", id); return categoryMapper.delete(wrapper) == 0 ? R.error() : R.ok(); } @Override public R getCategoryById(Integer id) { CategoryParentVo categoryParentVo = categoryMapper.getCategoryById(id); return categoryParentVo == null ? R.error() : R.ok().data("category", categoryParentVo); } @Override public R listCategory() { return R.ok().data("categoryList", categoryMapper.findCategoryList()); } } (4)控制层

这里我也是将所有的代码贴出来,自行需要删除

采用RESTful的接口风格,@Api相关的注解是 Swagger 的相关配置,用于接口测试,你用其他测试方法可以把这个删掉

/** * FileName: CategoryController * Author: 小袁 * Date: 2022/4/15 10:54 * Description: 分类栏目的控制层 */ @RestController @RequestMapping("/category") @Api(tags = "分类栏目控制层") public class CategoryController { @Autowired private CategoryService categoryService; /** * 新增分类栏目数据 * @param category * @return */ @PostMapping public R insertCategory(@RequestBody Category category) { return categoryService.insert(category); } /** * 根据ID删除分类栏目 * @param id * @return */ @DeleteMapping("{id}") @ApiOperation(value = "根据ID删除所有子分类栏目(包括父级分类如果有)") public R removeCategoryById(@PathVariable(value = "id") Integer id) { return categoryService.remove(id); } @PutMapping public R modifyCategoryById(@RequestBody Category category) { return categoryService.modify(category); } /** * 查询所有分类的目录结构 * @return */ @GetMapping @ApiOperation(value = "查询所有分类的目录结构") public R getCategoryList() { return categoryService.listCategory(); } /** * 根据ID获取对象 * @param id * @return */ @GetMapping("{id}") @ApiOperation(value = "根据ID获取对象") public R getCategoryById(@PathVariable(value = "id") Integer id) { return categoryService.getCategoryById(id); } } 六、Vo对象

一会接收SQL多级查询结果要用到的,也叫视图对象(View Object),返回给前端看的

父级分类

/** * FileName: CategoryVo * Author: 小袁 * Date: 2022/4/15 14:16 * Description: */ @Data public class CategoryParentVo { // 父级分类编号ID private Integer parentId; // 父级分类名称 private String parentName; // 子分类 private List childrenCategory; }

子分类

/** * FileName: CategoryChildrenVo * Author: 小袁 * Date: 2022/4/15 14:18 * Description: 子分类 */ @Data public class CategoryChildrenVo { // ID编号 private Integer childrenId; // 分类栏目名称 private String childrenName; } 七、MyBatis多级分类查询 (1)在resources目录下创建CategoryMapper.xml静态文件

用来写SQL语句的

别忘了在 application 加上mapper映射路径 在这里插入图片描述

(2)设计模式

回顾一下刚刚的数据格式,有点像什么?细心的同学已经发现了,没错,是不是和 JSON 数据格式有点类似?

将父级分类(Java、实战项目教学等)对应一个CategoryParentVo类

将每个父级分类的所有子分类对应一个List集合

每个CategoryParentVo有一个字分类的集合属性变量

看懂上面三句话就说明你已经掌握了,看不懂的结合创建Vo类看一下

在这里插入图片描述

(3)自定义返回类型模板(重点)

MyBatis的知识哦,不知道大伙忘了没?

(4)编写SQL

完整的CategoryMapper.xml

select x.id as parentId, x.name as parentName, y.id as childrenId ,y.name as childrenName from xy_category x left join xy_category as y on y.parent_id = x.id where x.parent_id = 0 select x.id as parentId, x.name as parentName, y.id as childrenId ,y.name as childrenName from xy_category x left join xy_category as y on y.parent_id = x.id where x.id = #{id} 八、Swagger接口测试

我这个项目整合了 Swagger 进行接口测试,网上很多整合的教程,只需要加一个配置类就搞定了,一分钟就行,我这里附上吧

依赖

io.springfox springfox-swagger2 2.7.0 io.springfox springfox-swagger-ui 2.7.0 /** * FileName: SwaggerConfig * Author: 小袁 * Date: 2022/3/11 19:09 * Description: */ @Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket webApiConfig(){ return new Docket(DocumentationType.SWAGGER_2) .groupName("webApi") .apiInfo(webApiInfo()) .select() .paths(Predicates.not(PathSelectors.regex("/admin/.*"))) .paths(Predicates.not(PathSelectors.regex("/error.*"))) .build(); } private ApiInfo webApiInfo(){ return new ApiInfoBuilder() .title("Swagger接口测试") .description("小袁同学") .version("1.0") .contact(new Contact("Helen", "http://www.baidu.com", "[email protected]")) .build(); } }

打开网页进行测试 在这里插入图片描述 执行查询所有分类的接口,测试结果如下,ok完美获取数据 在这里插入图片描述在这里插入图片描述 或者直接在浏览器访问请求路径测试 在这里插入图片描述

都看到这里啦,点点赞呀😋 感谢阅读😘


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3